package com.example.framework509.common.services.Impl.base;

import com.example.framework509.common.exceptions.FieldValueException;
import org.apache.commons.codec.digest.DigestUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public abstract class BaseReflectionServiceImpl<E> {

    /**
     * 获取业务对象的类型
     *
     * @return 业务对象的类型
     */
    protected Class<?> getEntityClass() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType_This = (ParameterizedType) type;
            Type entityType = parameterizedType_This.getActualTypeArguments()[0];
            return (Class<?>) entityType;
        }
        return Object.class;
    }

    protected Class<?> getIndexEntityClass(Integer index) {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType_This = (ParameterizedType) type;
            Type entityType = parameterizedType_This.getActualTypeArguments()[index];
            return (Class<?>) entityType;
        }
        return Object.class;
    }

    /**
     * 获取对象的字段值
     *
     * @param entity-对象
     * @param fieldName-对象包含的字段名
     * @return 对象的字段值
     * @throws NoSuchFieldException-对象不包含该名称的字段
     * @throws IllegalAccessException-字段值获取失败
     */
    protected Object getFieldValue(Object entity, String fieldName) {
        try {
            Field idField = entity.getClass().getDeclaredField(fieldName);
            idField.setAccessible(true);
            return idField.get(entity);
        } catch (IllegalAccessException | NoSuchFieldException e) {
            throw new FieldValueException();
        }
    }

    /**
     * 设置对象的字段值
     *
     * @param entity-对象
     * @param fieldName-对象包含的字段名
     * @param value-要设置的值
     * @throws NoSuchFieldException-对象不包含该名称的字段
     * @throws IllegalAccessException-要设置的值与字段类型不一致
     */
    protected void setFieldValue(Object entity, String fieldName, Object value) {
        try {
            Field field = entity.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(entity, value);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new FieldValueException();
        }
    }

    /**
     * 将驼峰式命名的字符串转换为下划线小写方式。如果转换前的驼峰式命名的字符串为空，则返回空字符串。
     * 例如：userName->user_name
     *
     * @param name 转换前的驼峰式命名的字符串
     * @return 转换后下划线小写方式命名的字符串
     */
    public static String underscoreName(String name) {
        StringBuilder result = new StringBuilder();
        if (name != null && name.length() > 0) {
            // 将第一个字符处理成小写
            result.append(name.substring(0, 1).toLowerCase());
            // 循环处理其余字符
            for (int i = 1; i < name.length(); i++) {
                String s = name.substring(i, i + 1);
                // 在大写字母前添加下划线
                if (s.equals(s.toUpperCase()) && !Character.isDigit(s.charAt(0))) {
                    result.append("_");
                }
                // 其他字符直接转成小写
                result.append(s.toLowerCase());
            }
        }
        return result.toString();
    }

    /**
     * 将下划线小写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。
     * 例如：user_name->userName
     *
     * @param name 转换前的下划线小写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     */
    public static String camelName(String name) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (name == null || name.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!name.contains("_")) {
            // 不含下划线，仅将首字母小写
            return name.substring(0, 1).toLowerCase() + name.substring(1);
        }
        // 用下划线将原始字符串分割
        String[] camels = name.split("_");
        for (String camel : camels) {
            // 跳过原始字符串中开头、结尾的下换线或双重下划线
            if (camel.isEmpty()) {
                continue;
            }
            // 处理真正的驼峰片段
            if (result.length() == 0) {
                // 第一个驼峰片段，全部字母都小写
                result.append(camel.toLowerCase());
            } else {
                // 其他的驼峰片段，首字母大写
                result.append(camel.substring(0, 1).toUpperCase());
                result.append(camel.substring(1).toLowerCase());
            }
        }
        return result.toString();
    }

    /**
     * @Description: 将List按page和pageSize进行分页返回
     * @Param: 装有实体的List；页码；每页条数
     * @return: 包含分页实体的List
     */
    public <T> List<T> pageList(List<T> list, Integer page, Integer size) {
        if (size < 1 || page < 0 || list.size() == 0)
            return new ArrayList<>();
        double ceil = Math.ceil((float) list.size() / size);
        int pages = Integer.parseInt(String.valueOf(ceil).split("\\.")[0]);
        if (page >= pages) return new ArrayList<>();
        List<T> resList = new ArrayList<>();
        for (int i = page * size; i < list.size() && i < (page + 1) * size; i++) {
            resList.add(list.get(i));
        }
        return resList;
    }

    /**
     * @Description: List集合差
     * @Param: 目标集合A；工具集合B
     * @return: 集合A-集合B，即集合A中含有的而集合B不含有的
     */
    public <T> List<T> listSubtraction(List<T> target, List<T> tool) {
        List<T> A = new ArrayList<>(target);
        List<T> B = new ArrayList<>(tool);
        A.removeAll(B);
        return A;
    }

    public String getMd5(List<Object> valuesList) {
        String[] strings = new String[valuesList.size()];
        for (int i = 0; i < valuesList.size(); i++) {
            strings[i] = valuesList.get(i) == null ? "null" : valuesList.get(i).toString();
        }
        return getMd5(strings);
    }

    public String getMd5(String[] valuesArray) {
        Arrays.sort(valuesArray);
        StringBuilder stringBuilder = new StringBuilder();
        for (Object value : valuesArray) {
            stringBuilder.append("&&").append(value);
        }
        return DigestUtils.md5Hex(stringBuilder.toString());
    }

    public String toLower(String value) {
        return Character.toLowerCase(value.charAt(0)) + value.substring(1);
    }

    public String toUpper(String value) {
        return Character.toUpperCase(value.charAt(0)) + value.substring(1);
    }

}
